package besta.moon.sql.expression.function.numeric;

import besta.moon.sql.datatype.Money;
import besta.moon.sql.datatype.MutableNumeric;
import besta.moon.sql.parser.SQLTokenizer;
import besta.moon.sql.expression.function.FunctionReturnP1;

public class FunctionAbs extends FunctionReturnP1 {

    @Override
    public int getFunction() {
        return SQLTokenizer.ABS;
    }

    @Override
    public boolean getBoolean() throws Exception {
        return getDouble() != 0;
    }

    @Override
    public int getInt() throws Exception {
        return Math.abs(param1.getInt());
    }

    @Override
    public long getLong() throws Exception {
        return Math.abs(param1.getLong());
    }

    @Override
    public float getFloat() throws Exception {
        return Math.abs(param1.getFloat());
    }

    @Override
    public double getDouble() throws Exception {
        return Math.abs(param1.getDouble());
    }

    @Override
    public long getMoney() throws Exception {
        return Math.abs(param1.getMoney());
    }

    @Override
    public MutableNumeric getNumeric() throws Exception {
        if (param1.isNull()) {
            return null;
        }
        MutableNumeric num = param1.getNumeric();
        if (num.getSignum() < 0) {
            num.setSignum(1);
        }
        return num;
    }

    @Override
    public Object getObject() throws Exception {
        if (param1.isNull()) {
            return null;
        }
        Object para1 = param1.getObject();
        switch (param1.getDataType()) {
            case SQLTokenizer.FLOAT, SQLTokenizer.DOUBLE -> {
                double dValue = ((Double) para1);
                return (dValue < 0) ? Double.valueOf(-dValue) : para1;
            }
            case SQLTokenizer.REAL -> {
                double fValue = ((Float) para1);
                return (fValue < 0) ? -fValue: para1;
            }
            case SQLTokenizer.BIGINT -> {
                long lValue = ((Number) para1).longValue();
                return (lValue < 0) ? Long.valueOf(-lValue) : para1;
            }
            case SQLTokenizer.TINYINT, SQLTokenizer.SMALLINT, SQLTokenizer.INT -> {
                int iValue = ((Number) para1).intValue();
                return (iValue < 0) ? Integer.valueOf(-iValue) : para1;
            }
            case SQLTokenizer.NUMERIC, SQLTokenizer.DECIMAL -> {
                MutableNumeric nValue = (MutableNumeric) para1;
                if (nValue.getSignum() < 0) {
                    nValue.setSignum(1);
                }
                return nValue;
            }
            case SQLTokenizer.MONEY -> {
                Money mValue = (Money) para1;
                if (mValue.value < 0) {
                    mValue.value = -mValue.value;
                }
                return mValue;
            }
            default -> throw createUnspportedDataType(param1.getDataType());
        }
    }

    @Override
    public String getString() throws Exception {
        Object obj = getObject();
        if (obj == null) {
            return null;
        }
        return obj.toString();
    }

}
